//
// Created by zxh on 2020-6-16.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <fcntl.h>
#include <strings.h>
#include <pthread.h>

#include "tcpServer.h"
#include "common.h"
#include "env_ctrol_service.h"

unsigned char tcpClientDataBuff[256] = {0x00};
unsigned char tcpClientDataBuffLen = 0x00;

int sockfd = 0x00;

/**非阻塞读*/
int read_data(int fd ,unsigned char *recvbuf,unsigned int recvbuflen)
{

    int ret = 0x00;

    fd_set rfds;
    struct timeval tv;

    if (fd < 0) {
        return (-1);
    }

    tv.tv_sec= 2;
    tv.tv_usec= 0;

    FD_ZERO(&rfds);
    FD_SET(fd, &rfds);

//    LOGI("recv ---------------------------------");
//    LOGI("fd :%d",fd);
//    LOGI("recvbuflen:%d",recvbuflen);

    if (select(1+fd, &rfds, NULL, NULL, &tv)>0)
    {
        /*有数据可*/
        if (FD_ISSET(fd, &rfds))
        {
            ret = recv(fd, recvbuf ,recvbuflen,0);
        }
    }
    else
    {
        ret = -1;
        LOGI("tcp service recv time out");
    }

    return (ret);
}

int write_data(int fd ,unsigned char * sendbuf,unsigned int len)
{
    if (fd < 0)
        return 0;

    if (len < 0)
        return 0;

    write(fd, sendbuf, len);
    return 0;
}

/**
*
*说明: 根据网卡信息查询本地IP地址
*ifname :eth0
*ip :ip地址
*
*
*
*
*/
int get_ip(const char *ifname, char *ip)
{
    int sock_get_ip;
    int s32Ret = 0;
    char ipaddr[48];
    struct sockaddr_in *sin;
    struct ifreq ifr;

    if((sock_get_ip = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        printf("socket create failed!\r\n");
        return -1;
    }

    memset(&ifr,0, sizeof(ifr));
    memcpy(ifr.ifr_name, ifname, strlen(ifname));

    if(ioctl(sock_get_ip, SIOCGIFADDR, &ifr) <0)
    {
        perror("ioctl error!\n");
        s32Ret = -2;
        goto FAILED;
    }

    sin = (struct sockaddr_in*)&ifr.ifr_addr;
    if(NULL != ip) strcpy(ip, inet_ntoa(sin->sin_addr));

    FAILED:
    close(sock_get_ip);
    return s32Ret;
}


void get_peer_ip_port(int fd, char **ip, int *port)
{

    int client_fd = fd;

    // discovery client information
    struct sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);

    if(getpeername(client_fd, (struct sockaddr*)&addr, &addrlen) == -1)
    {
        //fprintf(stderr,"discovery client information failed, fd=%d, errno=%d(%#x).\n", client_fd, errno, errno);
        return;
    }

    // ip v4 or v6
    char *buf = malloc(INET6_ADDRSTRLEN);
    memset(buf, 0, INET6_ADDRSTRLEN);

    //char *buf = new   char[INET6_ADDRSTRLEN+1]; "\0";


    if((inet_ntop(addr.sin_family, &addr.sin_addr, buf, INET6_ADDRSTRLEN)) == NULL)
    {
        //fprintf(stderr,"convert client information failed, fd=%d, errno=%d(%#x).\n", client_fd, errno, errno);
        return;

    }

    *port = ntohs(addr.sin_port);
    *ip = buf;

    return;
}

/**
*
*说明: net data recv send
*
*sockfd: sock fd
*
*
*
*/
int net_send_recv_proc(int sockfd)
{
    int ret = 0x00;

    /*read data*/

    /*send data*/

    return ret;

}

void* client_fun(void *arg)
{

    int i = 0x00;
    int ret = 0x00;
    int connfd = *(int*)arg;

    char *ip[4] = {NULL};
    int port = 0x00;

    int flags = 0x00;

    unsigned char len = 255;
    unsigned char datbuff[256] = {0x00};

    flags = fcntl(connfd, F_GETFL, 0);              //获取文件的flags值�?
    fcntl(connfd, F_SETFL, flags | O_NONBLOCK);   	//设置成非阻塞模式�?

    /**/
    get_peer_ip_port(connfd,ip,&port);
    free(ip[0]);

    LOGI("port :%d",port);
    LOGI("connfd :%d",connfd);

    while (1)
    {

        ret = read_data(connfd,datbuff,sizeof(datbuff));
//        LOGI("ret :%d!\n",ret);

        if (ret == 0x00)
        {
            break;
        }
        else if (ret > 0)
        {

//            for (i= 0x00;i < ret;i ++)
//            {
//                LOGI("%02x!",datbuff[i]);
//            }

            LogOutHexString((char *)datbuff,ret);

            tcpClientDataBuffLen = ret;
            memcpy(tcpClientDataBuff,datbuff,tcpClientDataBuffLen);


            write_data(connfd,datbuff,ret);
            memset(datbuff,0,ret);
        }
    }

    LOGI("client closed!\n");
    close(connfd);

    return NULL;
}

int init_tcp_server_param(void)
{
    int log;
    int  on;
    struct sockaddr_in server,client;

    LOGI("start sock!\n");

    /*查询本地IP地址*/
    bzero(&server,sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(8089);
    server.sin_addr.s_addr = htonl(INADDR_ANY);

    //创建套接�?
    sockfd = socket(AF_INET,SOCK_STREAM,0);

    /* Enable address reuse */
    on = 1;
    setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );

    if(sockfd < 0)
    {

        LOGI(".socket create error......!\n");
        sleep(10);

        close(sockfd);
        return sockfd;
    }

    log = bind(sockfd,(struct sockaddr*)&server,sizeof(server));
    if(log < 0)
    {
        LOGI(".bindfd error......!\n");
        sleep(10);

        close(sockfd);
        return log;
    }

    log = listen(sockfd,20);
    if(log < 0)
    {
        LOGI(".listen error......!\n");
        sleep(10);

        close(sockfd);
        return log;
    }

    LOGI("waiting client >>>>>\n");
    return sockfd;
}

void * tcp_server_proc(void * arg)
{

    int connfd;
    pthread_t thread_id;

    struct sockaddr_in client;

    LOGI("--------------tcp server wait connect------------------!\n");
    LOGI("tcp server fd :%d",sockfd);

    while(1)
    {

        socklen_t client_len = sizeof(client);

        LOGI("....................... wait connect!\n");
        connfd = accept(sockfd,(struct sockaddr*)&client,&client_len);
        if(connfd < 0)
        {
            printf("connfd error\n");
            continue;
        }

        LOGI("connfd :%d",connfd);

        LOGI("....................... connect ok!\n");
        char cli_ip[INET_ADDRSTRLEN] = "";

        inet_ntop(AF_INET, &client.sin_addr, cli_ip, INET_ADDRSTRLEN);
        //printf("----------------------------------------------\n");
        //printf("client ip=%s,port=%d\n", cli_ip,ntohs(client.sin_port));

        LOGI("----------------------------------------------\n");
        LOGI("client ip=%s,port=%d\n", cli_ip,ntohs(client.sin_port));

        pthread_create(&thread_id,NULL,client_fun,(void*)&connfd);
        pthread_detach(thread_id);//线程分离，结束时自动回收线程

    }

    LOGI("end sock!\n");
    close(sockfd);

    return 0;
}



